package com.ittao.taoaicodemother.manage.storage.lifecycle.observer;

import com.ittao.taoaicodemother.config.AppStorageConfig;
import com.ittao.taoaicodemother.manage.storage.entity.SessionInfo;
import com.ittao.taoaicodemother.manage.storage.service.TempDirectoryService;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.concurrent.*;

/**
 * 临时文件生命周期观察者
 * 负责监控会话活动并管理临时文件的生命周期
 *
 * 核心功能：
 * 1. 监听会话活动事件
 * 2. 根据配置的延迟时间管理文件清理
 * 3. 当有新的对话活动时重置清理时间
 */
@Slf4j
@Component
public class TempFileLifecycleObserver implements SessionActivityObserver {

    private final AppStorageConfig appStorageConfig;
    private final ScheduledExecutorService cleanupScheduler;

    @Resource
    private TempDirectoryService tempDirectoryService;

    /**
     * 会话信息映射：sessionId -> SessionInfo
     */
    private final ConcurrentHashMap<String, SessionInfo> sessionMap = new ConcurrentHashMap<>();

    public TempFileLifecycleObserver(AppStorageConfig appStorageConfig) {
        this.appStorageConfig = appStorageConfig;
        this.cleanupScheduler = Executors.newScheduledThreadPool(2, r -> {
            Thread t = new Thread(r, "temp-file-lifecycle-cleanup");
            t.setDaemon(true);
            return t;
        });
    }

    @PostConstruct
    public void init() {
        log.info("临时文件生命周期观察者初始化完成，清理延迟时间: {}秒",
                appStorageConfig.getCos().getCleanupDelaySeconds());
    }

    @PreDestroy
    public void destroy() {
        if (cleanupScheduler != null && !cleanupScheduler.isShutdown()) {
            cleanupScheduler.shutdown();
            try {
                if (!cleanupScheduler.awaitTermination(10, TimeUnit.SECONDS)) {
                    cleanupScheduler.shutdownNow();
                }
            } catch (InterruptedException e) {
                cleanupScheduler.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }

        // 清理所有会话
        cleanupAllSessions();
    }

    @Override
    public void onSessionActivity(SessionActivityEvent event) {
        String sessionId = event.getSessionId();

        switch (event.getActivityType()) {
            case PROJECT_GENERATION_START:
                handleProjectGenerationStart(event);
                break;

            case PROJECT_GENERATION_COMPLETE:
                handleProjectGenerationComplete(event);
                break;

            case USER_CONVERSATION:
            case PROJECT_MODIFICATION:
                handleUserActivity(event);
                break;

            case SESSION_END:
            case MANUAL_CLEANUP:
                handleSessionEnd(event);
                break;

            default:
                log.debug("未处理的会话活动类型: {}, sessionId: {}",
                        event.getActivityType(), sessionId);
        }
    }

    @Override
    public String getObserverName() {
        return "TempFileLifecycleObserver";
    }

    /**
     * 处理项目生成开始事件
     */
    private void handleProjectGenerationStart(SessionActivityEvent event) {
        String sessionId = event.getSessionId();

        SessionInfo sessionInfo = new SessionInfo(
                sessionId,
                event.getUserId(),
                event.getAppId(),
                event.getTempFilePath(),
                LocalDateTime.now()
        );

        sessionMap.put(sessionId, sessionInfo);

        log.info("注册会话临时文件监控: sessionId={}, tempPath={}",
                sessionId, event.getTempFilePath());
    }

    /**
     * 处理项目生成完成事件
     */
    private void handleProjectGenerationComplete(SessionActivityEvent event) {
        String sessionId = event.getSessionId();
        SessionInfo sessionInfo = sessionMap.get(sessionId);

        if (sessionInfo != null) {
            // 更新最后活动时间
            sessionInfo.updateLastActivityTime();

            // 调度清理任务
            scheduleCleanupTask(sessionInfo);

            log.info("项目生成完成，调度清理任务: sessionId={}, 将在{}秒后清理",
                    sessionId, appStorageConfig.getCos().getCleanupDelaySeconds());
        }
    }

    /**
     * 处理用户活动事件（对话、修改等）
     */
    private void handleUserActivity(SessionActivityEvent event) {
        String sessionId = event.getSessionId();
        SessionInfo sessionInfo = sessionMap.get(sessionId);

        if (sessionInfo != null) {
            // 更新最后活动时间
            sessionInfo.updateLastActivityTime();

            // 取消之前的清理任务并重新调度
            sessionInfo.cancelCleanupTask();
            scheduleCleanupTask(sessionInfo);

            log.debug("用户活动检测，重置清理时间: sessionId={}, activityType={}",
                    sessionId, event.getActivityType());
        }
    }

    /**
     * 处理会话结束事件
     */
    private void handleSessionEnd(SessionActivityEvent event) {
        String sessionId = event.getSessionId();
        SessionInfo sessionInfo = sessionMap.remove(sessionId);

        if (sessionInfo != null) {
            // 取消清理任务
            sessionInfo.cancelCleanupTask();

            // 立即清理临时文件
            cleanupSessionFiles(sessionInfo);

            log.info("会话结束，立即清理临时文件: sessionId={}", sessionId);
        }
    }

    /**
     * 调度清理任务
     */
    private void scheduleCleanupTask(SessionInfo sessionInfo) {
        long delaySeconds = appStorageConfig.getCos().getCleanupDelaySeconds();

        // 调度清理任务
        var cleanupTask = cleanupScheduler.schedule(() -> {
            try {
                // 检查是否仍然需要清理（可能在延迟期间有新的活动）
                SessionInfo currentInfo = sessionMap.get(sessionInfo.getSessionId());
                if (currentInfo != null && currentInfo.equals(sessionInfo)) {
                    // 移除会话信息
                    sessionMap.remove(sessionInfo.getSessionId());

                    // 执行清理
                    cleanupSessionFiles(sessionInfo);

                    log.info("定时清理任务执行: sessionId={}, tempPath={}",
                            sessionInfo.getSessionId(), sessionInfo.getTempFilePath());
                }
            } catch (Exception e) {
                log.error("定时清理任务执行失败: sessionId={}, error={}",
                        sessionInfo.getSessionId(), e.getMessage(), e);
            }
        }, delaySeconds, TimeUnit.SECONDS);

        // 保存清理任务引用
        sessionInfo.setCleanupTask(cleanupTask);
    }

    /**
     * 清理会话文件
     */
    private void cleanupSessionFiles(SessionInfo sessionInfo) {
        if (sessionInfo.getTempFilePath() != null) {
            try {
                Path tempPath = Paths.get(sessionInfo.getTempFilePath());
                if (tempPath.toFile().exists()) {
                    // 清理主要的临时目录
                    tempDirectoryService.cleanupTempDirectory(sessionInfo.getTempFilePath());

                    // 检查并清理相关的code_deploy目录
                    cleanupRelatedCodeDeployDirectory(sessionInfo);

                    // 注意：不再清理code_output目录，因为这些是用户的代码生成结果，应该保留
                    // cleanupRelatedCodeOutputDirectory(sessionInfo);

                    log.info("清理会话临时文件成功: sessionId={}, path={}",
                            sessionInfo.getSessionId(), sessionInfo.getTempFilePath());
                }
            } catch (Exception e) {
                log.error("清理会话临时文件失败: sessionId={}, path={}, error={}",
                        sessionInfo.getSessionId(), sessionInfo.getTempFilePath(), e.getMessage(), e);
            }
        }
    }

    /**
     * 清理相关的code_deploy目录
     */
    private void cleanupRelatedCodeDeployDirectory(SessionInfo sessionInfo) {
        try {
            String userId = sessionInfo.getUserId();
            String appId = sessionInfo.getAppId();

            if (userId != null && appId != null) {
                // 构建code_deploy目录路径
                String cosBasePath = appStorageConfig.getCos().getTempDirPath();
                Path codeDeployBasePath = Paths.get(cosBasePath, userId, "code_deploy");

                if (Files.exists(codeDeployBasePath)) {
                    // 查找与当前appId相关的deployKey目录
                    try (var stream = Files.list(codeDeployBasePath)) {
                        stream.filter(Files::isDirectory)
                                .forEach(deployKeyDir -> {
                                    try {
                                        // 检查目录的最后修改时间，如果超过清理阈值则删除
                                        long lastModified = Files.getLastModifiedTime(deployKeyDir).toMillis();
                                        long cleanupThreshold = System.currentTimeMillis() -
                                                (appStorageConfig.getCos().getCleanupDelaySeconds() * 1000L);

                                        if (lastModified < cleanupThreshold) {
                                            tempDirectoryService.cleanupTempDirectory(deployKeyDir.toString());
                                            log.info("清理相关code_deploy目录: sessionId={}, deployPath={}",
                                                    sessionInfo.getSessionId(), deployKeyDir);
                                        }
                                    } catch (Exception e) {
                                        log.warn("清理code_deploy目录失败: {}, error={}",
                                                deployKeyDir, e.getMessage());
                                    }
                                });
                    }
                }
            }
        } catch (Exception e) {
            log.warn("清理相关code_deploy目录时发生异常: sessionId={}, error={}",
                    sessionInfo.getSessionId(), e.getMessage());
        }
    }

    /**
     * 清理相关的code_output目录
     */
    private void cleanupRelatedCodeOutputDirectory(SessionInfo sessionInfo) {
        try {
            String userId = sessionInfo.getUserId();
            String appId = sessionInfo.getAppId();

            if (userId != null && appId != null) {
                // 构建code_output目录路径
                String cosBasePath = appStorageConfig.getCos().getTempDirPath();
                Path codeOutputBasePath = Paths.get(cosBasePath, userId, "code_output");

                if (Files.exists(codeOutputBasePath)) {
                    // 查找与当前appId相关的项目目录
                    try (var stream = Files.list(codeOutputBasePath)) {
                        stream.filter(Files::isDirectory)
                                .filter(projectDir -> {
                                    String dirName = projectDir.getFileName().toString();
                                    // 匹配格式：vue_project_appId, html_appId, multi_file_appId
                                    return dirName.endsWith("_" + appId);
                                })
                                .forEach(projectDir -> {
                                    try {
                                        // 检查目录的最后修改时间，如果超过清理阈值则删除
                                        long lastModified = Files.getLastModifiedTime(projectDir).toMillis();
                                        long cleanupThreshold = System.currentTimeMillis() -
                                                (appStorageConfig.getCos().getCleanupDelaySeconds() * 1000L);

                                        if (lastModified < cleanupThreshold) {
                                            tempDirectoryService.cleanupTempDirectory(projectDir.toString());
                                            log.info("清理相关code_output目录: sessionId={}, outputPath={}",
                                                    sessionInfo.getSessionId(), projectDir);
                                        }
                                    } catch (Exception e) {
                                        log.warn("清理code_output目录失败: {}, error={}",
                                                projectDir, e.getMessage());
                                    }
                                });
                    }
                }
            }
        } catch (Exception e) {
            log.warn("清理相关code_output目录时发生异常: sessionId={}, error={}",
                    sessionInfo.getSessionId(), e.getMessage());
        }
    }

    /**
     * 清理所有会话
     */
    private void cleanupAllSessions() {
        log.info("开始清理所有会话临时文件，当前会话数量: {}", sessionMap.size());

        for (SessionInfo sessionInfo : sessionMap.values()) {
            sessionInfo.cancelCleanupTask();
            cleanupSessionFiles(sessionInfo);
        }

        sessionMap.clear();
        log.info("所有会话临时文件清理完成");
    }

    /**
     * 手动释放指定应用的监控资源
     * 用于应用删除或下线时释放相关的监控资源和定时任务
     * 注意：此方法只释放监控资源，不删除实际文件
     * 
     * @param appId 应用ID
     * @param userId 用户ID
     */
    public void manualCleanupByAppId(String appId, String userId) {
        if (appId == null || userId == null) {
            log.warn("手动释放监控资源失败：appId或userId为空");
            return;
        }

        int releasedCount = 0;
        
        // 使用迭代器安全地移除匹配的会话
        var iterator = sessionMap.entrySet().iterator();
        while (iterator.hasNext()) {
            var entry = iterator.next();
            SessionInfo sessionInfo = entry.getValue();
            
            // 匹配appId和userId
            if (appId.equals(sessionInfo.getAppId()) && userId.equals(sessionInfo.getUserId())) {
                // 取消定时清理任务
                sessionInfo.cancelCleanupTask();
                
                // 注意：这里只释放监控资源，不删除实际文件
                // 文件的删除应该由具体的业务逻辑（如undeploy、delete）来决定
                
                // 从映射中移除
                iterator.remove();
                
                releasedCount++;
                log.info("释放应用监控资源: sessionId={}, appId={}, userId={}", 
                        sessionInfo.getSessionId(), appId, userId);
            }
        }
        
        log.info("应用监控资源释放完成: appId={}, userId={}, 释放会话数量={}", 
                appId, userId, releasedCount);
    }
}